﻿namespace NTLib.Core.Collection.Tree
{
    using Manipulators;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Args;
    using System.Threading;
    using Pool;
    using Memory;
    using Exceptions.Collection;
    using Threading;

    /// <summary>
    /// Tree collection used to store an <typeparamref name="TValue" /> in a tree leaf.
    /// All the level used to access the leaf search are compose by one <typeparamref name="TSeq" /> element.
    /// Really Quick to search into an big quantity of elements but slow to add or remove.
    /// </summary>
    /// <typeparam name="TKey">The type of the key.</typeparam>
    /// <typeparam name="TValue">The type of the value.</typeparam>
    /// <typeparam name="TSeq">The type of the seq.</typeparam>
    /// <typeparam name="TLocker">The type of the locker.</typeparam>
    /// <seealso cref="System.Collections.Generic.IDictionary{TKey, TValue}" />
    public class TreeCollection<TKey, TValue, TSeq, TLocker> : Disposable, IDictionary<TKey, TValue>, ISealed
        where TLocker : ILocker, new()
    {
        #region Fields

        private static readonly ObjectPool<TreeLevelNode<TSeq, TValue>> s_poolLevel;
        private static readonly ObjectPool<TreeLeafNode<TSeq, TValue>> s_poolLeaf;

        private readonly List<TKey> _keys;
        private readonly List<TValue> _values;

        private readonly ReadOnlyCollection<TKey> _roKeys;
        private readonly ReadOnlyCollection<TValue> _roValues;

        private readonly TreeLevelNode<TSeq, TValue> _root;
        private readonly ISenquensor<TKey, TSeq> _defaultSequensor;
        private TLocker _locker;

        #endregion

        #region Ctor

        /// <summary>
        /// Initializes the <see cref="TreeCollection{TKey, TValue, TSeq, TLocker}" /> class.
        /// </summary>
        static TreeCollection()
        {
            throw new NotImplementedException("Not finished");

            s_poolLeaf = new ObjectPool<TreeLeafNode<TSeq, TValue>>();
            s_poolLevel = new ObjectPool<TreeLevelNode<TSeq, TValue>>();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TreeCollection{TKey, TValue, TSeq, TLocker}" /> class.
        /// </summary>
        public TreeCollection(TLocker locker = default(TLocker))
        {
            throw new NotImplementedException("Not finished");


            if (EqualityComparer<TLocker>.Default.Equals(locker, default(TLocker)))
                locker = new TLocker();

            this._locker = locker;
            this._root = s_poolLevel.Get();
            this._keys = new List<TKey>();
            this._values = new List<TValue>();

            this._roValues = new ReadOnlyCollection<TValue>(this._values);
            this._roKeys = new ReadOnlyCollection<TKey>(this._keys);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TreeCollection{TKey, TValue, TSeq, TLocker}"/> class.
        /// </summary>
        /// <param name="defaultSequensor">The default sequensor.</param>
        public TreeCollection(ISenquensor<TKey, TSeq> defaultSequensor)
            : this()
        {
            this._defaultSequensor = defaultSequensor;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets an <see cref="T:System.Collections.Generic.ICollection`1" /> containing the keys of the <see cref="T:System.Collections.Generic.IDictionary`2" />.
        /// </summary>
        public ICollection<TKey> Keys
        {
            get { return this._roKeys; }
        }

        /// <summary>
        /// Gets an <see cref="T:System.Collections.Generic.ICollection`1" /> containing the values in the <see cref="T:System.Collections.Generic.IDictionary`2" />.
        /// </summary>
        public ICollection<TValue> Values
        {
            get { return this._roValues; }
        }

        /// <summary>
        /// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.
        /// </summary>
        public int Count
        {
            get { return this._values.Count; }
        }

        /// <summary>
        /// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.
        /// </summary>
        public bool IsReadOnly
        {
            get { return this.IsSealed; }
        }

        public bool IsSealed
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public TValue this[TKey key]
        {
            get
            {
                throw new NotImplementedException();
            }
            set { Insert(key, value, true, this._defaultSequensor); }
        }

        #endregion

        #region Events

        public event EventHandler<ValueChangedEventArgs<bool>> SealedChanged;

        #endregion

        #region Methods

        /// <summary>
        /// Adds the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        public void Add(TKey key, TValue value)
        {
            Insert(key, value, false);
        }

        /// <summary>
        /// Adds the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <param name="sequensor">The senquensor.</param>
        public void Add(TKey key, TValue value, ISenquensor<TKey, TSeq> sequensor)
        {
            Insert(key, value, false, sequensor);
        }

        /// <summary>
        /// Determines whether the <see cref="T:System.Collections.Generic.IDictionary`2" /> contains an element with the specified key.
        /// </summary>
        /// <param name="key">The key to locate in the <see cref="T:System.Collections.Generic.IDictionary`2" />.</param>
        /// <returns>
        /// true if the <see cref="T:System.Collections.Generic.IDictionary`2" /> contains an element with the key; otherwise, false.
        /// </returns>
        public bool ContainsKey(TKey key)
        {
            return ContainsKey(key, this._defaultSequensor, false);
        }

        /// <summary>
        /// Determines whether the specified key contains key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="partialy">if set to <c>true</c> [partialy].</param>
        /// <returns>
        ///   <c>true</c> if the specified key contains key; otherwise, <c>false</c>.
        /// </returns>
        public bool ContainsKey(TKey key, bool partialy)
        {
            return ContainsKey(key, this._defaultSequensor, partialy);
        }

        /// <summary>
        /// Determines whether the specified key contains key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="sequensor">The sequensor.</param>
        /// <param name="partialy">if set to <c>true</c> [partialy].</param>
        /// <returns>
        ///   <c>true</c> if the specified key contains key; otherwise, <c>false</c>.
        /// </returns>
        public bool ContainsKey(TKey key, ISenquensor<TKey, TSeq> sequensor, bool partialy)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Removes the element with the specified key from the <see cref="T:System.Collections.Generic.IDictionary`2" />.
        /// </summary>
        /// <param name="key">The key of the element to remove.</param>
        /// <returns>
        /// true if the element is successfully removed; otherwise, false.  This method also returns false if <paramref name="key" /> was not found in the original <see cref="T:System.Collections.Generic.IDictionary`2" />.
        /// </returns>
        public bool Remove(TKey key)
        {
            return Remove(key, this._defaultSequensor, false);
        }

        /// <summary>
        /// Removes the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="partialy">if set to <c>true</c> [partialy].</param>
        /// <returns></returns>
        public bool Remove(TKey key, bool partialy)
        {
            return Remove(key, this._defaultSequensor, partialy);
        }

        public bool Remove(TKey key, ISenquensor<TKey, TSeq> sequensor, bool partialy)
        {
            throw new NotImplementedException();
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            return TryGetValue(key, out value, null);
        }

        public bool TryGetValue(TKey key, out TValue value, ISenquensor<TKey, TSeq> sequensor)
        {
            throw new NotImplementedException();
        }

        public bool TryGetValues(TKey partialKey, out IEnumerable<TValue> value, ISenquensor<TKey, TSeq> sequensor = null)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1" />.
        /// </summary>
        /// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
        public void Add(KeyValuePair<TKey, TValue> item)
        {
            Insert(item.Key, item.Value, false);
        }

        /// <summary>
        /// Adds the specified item.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="sequensor">The sequensor.</param>
        public void Add(KeyValuePair<TKey, TValue> item, ISenquensor<TKey, TSeq> sequensor)
        {
            Insert(item.Key, item.Value, false, sequensor);
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1" /> contains a specific value.
        /// </summary>
        /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
        /// <returns>
        /// true if <paramref name="item" /> is found in the <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, false.
        /// </returns>
        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return ContainsKey(item.Key, null, false);
        }

        /// <summary>
        /// Determines whether [contains] [the specified item].
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="sequensor">The sequensor.</param>
        /// <param name="partialy">if set to <c>true</c> [partialy].</param>
        /// <returns>
        ///   <c>true</c> if [contains] [the specified item]; otherwise, <c>false</c>.
        /// </returns>
        public bool Contains(KeyValuePair<TKey, TValue> item, ISenquensor<TKey, TSeq> sequensor, bool partialy = false)
        {
            return ContainsKey(item.Key, sequensor, partialy);
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            return Remove(item, this._defaultSequensor);
        }

        public bool Remove(KeyValuePair<TKey, TValue> item, ISenquensor<TKey, TSeq> senquensor, bool partialy = false)
        {
            throw new NotImplementedException();
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        public void Sealed(CancellationToken token = default(CancellationToken))
        {
            throw new NotImplementedException();
        }

        private void Insert(TKey key, TValue value, bool replace = false, ISenquensor<TKey, TSeq> sequensor = null)
        {
            if (sequensor == null)
                sequensor = this._defaultSequensor;

            if (sequensor == null)
                throw new SequensorMissingException(typeof(TKey), typeof(TSeq));

            var keyParts = sequensor.Senquence(key);

            this._root.Insert(keyParts, 0, replace, value);
        }

        #endregion
    }
}
